package com.xuliugen.spring.ioc.factory;

import com.xuliugen.spring.ioc.config.Bean;
import com.xuliugen.spring.ioc.parse.ConfigManager;
import com.xuliugen.spring.ioc.utils.BeanUtil;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * 在ClassPathXmlApplicationContext创建的时候创建所有Bean的实例，就是初始化Spring容器
 * Created by xuliugen on 2017/12/13.
 */
public class ClassPathXmlApplicationContext implements BeanFactory {

    private Map<String, Bean> config;

    /**
     * 使用Map作为Spring容器，放置初始化的Bean
     */
    private Map<String, Object> context = new HashMap<>();

    /**
     * 初始化构造方法
     * @param path 配置文件的路径
     */
    public ClassPathXmlApplicationContext(String path) {
        //1、获取配置文件需要初始化的Bean信息
        config = ConfigManager.getConfig(path);
        //2、遍历配置初始化Bean
        if (config != null) {
            config.forEach((beanName, bean) -> {
                //3、将初始化的Bean放入容器
                context.put(beanName, createBean(bean));
            });
        }
    }

    /**
     * 根据Bean创建Bean元素
     * @param bean
     * @return
     */
    private Object createBean(Bean bean) {
        //1、或得要创建的Bean的Class
        String className = bean.getClassName();
        Class clazz;
        try {
            clazz = Class.forName(className);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            throw new RuntimeException("请检查Bean的Class配置是否正确！");
        }
        //创建class对应的对象
        try {
            //调用空参构造
            Object beanObj = clazz.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("Bean没有空参的构造方法！");
        }

        //2、需要获得Bean的属性，将其注入,注入分为两种：
        if (bean.getProperties() != null) {
            bean.getProperties().forEach(property -> {
                if (property.getValue() != null) {
                    //(1) 简单->value属性注入
                    String value = property.getValue();
                    String name = property.getName();
                    //根据属性获取对应的set方法
                    Method setMethod = BeanUtil.getWriteMethod(bean, name);
                    //调用set方法
                    try {
                        setMethod.invoke(bean, value);
                    } catch (Exception e) {
                        e.printStackTrace();
                        throw new RuntimeException("Bean的属性" + name + "没有对应的set方法，或方法设置错误！");
                    }
                }
                if (property.getRef() != null) {
                    //(2) 复杂->其他Bean的依赖注入
                    String ref = property.getRef();
                }
            });
        }
        return null;
    }

    @Override
    public Object getBean(String beanName) {
        return null;
    }
}
